package main

import (
	"fmt"
	"strconv"
)

const typeName = 1

func main() {
	fmt.Println("hello world")
	//var s = test()

	//fmt.Println(s)

	//noLengthArr()

	goMap()
}

// 左花括号必须写同行
func test() string {

	name := "hello world"

	ptr := &name

	fmt.Println("ptr" + *ptr)

	fmt.Println("ptr point", ptr)

	age := new(string)

	*age = "aes"

	fmt.Println("age", *age)

	fmt.Println("age ptr", age)

	fmt.Println("栈上指针", *testPtr())

	fmt.Println("")

	nullPtr := "hell"

	//if 就算有一行也必须使用大括号
	if &nullPtr == nil {
		fmt.Println("空指针")
	} else {
		fmt.Println("非空指针")
	}

	fmt.Println("空指针", &nullPtr == nil)

	fmt.Println(len(nullPtr))

	for i := 0; i < len(nullPtr); i++ {
		fmt.Printf("%c\n", nullPtr[i])
	}

	arr()
	return ""
}

func testPtr() *string {
	city := "DL"

	return &city
}

func arr() {

	fmt.Println("array")

	//定义数组
	nums := [10]int{1}

	//普通遍历，len获取数组长度
	for i := 0; i < len(nums); i++ {
		fmt.Printf("%d", nums[i])
	}

	fmt.Printf("\n")

	//range遍历,key和value是一个副本，换句话说修改key和value的值不会影响到原数组
	for key, value := range nums {
		value++
		nums[key] = value + 1
		fmt.Println("key:", key, "value:", value)
		fmt.Println("数组", nums)
	}

	fmt.Println(nums)

}

/*
*
不定长数组(切片)slice
*/
func noLengthArr() {

	fmt.Println("不定长数组============")

	arr := []int{1, 2, 3}

	arr = append(arr, 4, 5, 6, 7, 8, 9)

	fmt.Println("arr", arr, "容量", cap(arr))

	fmt.Println("=============================>")

	fmt.Println("==================数组切片=========")

	//切片之后的数组修改的话会影响到原数组

	arr2 := arr[0:]

	fmt.Println("arr2", arr2)

	fmt.Println("===================从开头0开始切可以省略开头")

	arr3 := arr[:3]

	fmt.Println("arr3", arr3)

	fmt.Println("================切指定位置===================>")

	arr4 := arr[1:3]

	fmt.Println("arr4", arr4)

	fmt.Println("===================切到结尾的话可以省略后面的============>")

	arr5 := arr[3:]

	fmt.Println("arr5", arr5)

	modifySliceArray()

	//也可以基于一个字符串截取

	str := "hello world"[0:3]

	fmt.Println("字符串截取", str)
}

func modifySliceArray() {

	var arr []int

	arr = append(arr, 1, 2)

	arr1 := arr[:]

	arr1[0] = 1000

	fmt.Println("切片后的值修改", arr1, "原值", arr)

	//如果想让切片完全独立于原始数组，可以使用copy函数(也是自由函数)

	creatEmptySliceByMake()
}

/*
*
创建空切片使用make指定容量
*/
func creatEmptySliceByMake() {

	fmt.Println("创建空切片使用make指定容量")

	arr := make([]string, 3, 20)

	fmt.Println("我们创建了一个容量是20，当前长度是3的切片，这样可以减少内存消耗")

	for key, _ := range arr {
		arr[key] = strconv.Itoa(key + 1)
		fmt.Println("arr[key]", arr[key])
	}

	fmt.Println("arr", arr)

	arrayCopy()
}

func arrayCopy() {
	//数组的copy

	arr := make([]string, 3, 20)

	for key, _ := range arr {
		arr[key] = strconv.Itoa(key + 1)
	}

	arrCopy := make([]string, len(arr), cap(arr))

	copy(arrCopy, arr[:])

	for i := 0; i < len(arrCopy); i++ {
		fmt.Println("arr--", i, arrCopy[i])
	}
}

/*
*
字典
*/
func goMap() {

	//定义map

	var idNames map[int]string

	//此时map不能直接使用，因为是空的

	//分配空间，必须要分配空间,可以不指定长度，但是建议直接指定长度，这样性能更好
	idNames = make(map[int]string, 10)

	idNames[0] = "zs"

	for key, value := range idNames {
		fmt.Println("key", key, "value", value)
	}

	//定义map的第二种方式

	//定义时直接分配空间

	idAge := make(map[int]int, 10)

	idAge[11] = 11

	for i := 0; i < 12; i++ {
		idAge[i] = i
	}

	for key, _ := range idAge {

		value, ok := idAge[key]

		fmt.Println("key", key, "val", value, "contains", ok)

	}
	fmt.Println("idAge", idAge, "len idAge", len(idAge))

	//map不存在访问越界的问题，go认为所有的key都是有效的，所以访问一个不存在的key不会崩溃，会返回这个类型的0值
	//int:0,string:'',bool :false
	fmt.Println("idAge 100", idAge[100])

	//需要一个能够校验key是否存在的方式

	value, ok := idAge[200] //如果200这个key存在则ok返回true，否则返回false

	if ok == true {
		fmt.Println("key存在")
	} else {
		fmt.Println("key不存在")
	}

	fmt.Println("value,", value, "ok", ok)

	//删除指定key

	delete(idAge, 1000000)

	//TODO 并发任务处理时候需要对map上锁

}
